package com.lxm.ymcc.service.impl;

import com.lxm.ymcc.domain.CourseDoc;
import com.lxm.ymcc.dto.AggPageList;
import com.lxm.ymcc.dto.BucketVo;
import com.lxm.ymcc.dto.SearchDto;
import com.lxm.ymcc.mapper.HighlightResultMapper;
import com.lxm.ymcc.repository.CourseDocRepository;
import com.lxm.ymcc.result.PageList;
import com.lxm.ymcc.service.ISearchService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.management.Query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements ISearchService {
    @Autowired
    private CourseDocRepository repository;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;


    @Override
    public void save(CourseDoc doc) {
        repository.save(doc);
    }

    @Override
    public void del(Long id) {
        repository.deleteById(id);
    }

    private String orderName(String name){
        switch (name){
            case "xl": return "saleCount";
            case "pl": return "commentCount";
            case "jg": return "price";
            case "rq": return "viewCount";
            case "xp": return "onlineTime";
        }

        return "saleCount";
    }

    private SortOrder orderRule(String rule){
        return rule==""||rule.toLowerCase()=="desc"?SortOrder.DESC:SortOrder.ASC;
    }

    @Override
    public PageList<CourseDoc> searchCourse(SearchDto dto) {
        //1.构建查询对象
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        //2=====================添加分页条件========================
        searchQueryBuilder.withPageable(PageRequest.of(dto.getPage()-1,dto.getRows()));
        //3======================添加排序的条件=====================
        /*
            排序的字段 xl pl jg rq xp
            private String sortField;// 	"rq"
            排序的方式   desc
            private String sortType;// 	"desc"
            xl-->saleCount
            pl-->commentCount
            jg-->price
            rq-->viewCount
            xp-->onlineTime
         */
        if(StringUtils.hasLength(dto.getSortField())){
            //根据简称 选择排序的字段
            String ordeName = orderName(dto.getSortField());
            //排序的规则
            SortOrder sortOrder = orderRule(dto.getSortType());
            searchQueryBuilder.withSort(new FieldSortBuilder(ordeName).order(sortOrder));
        }
        //4======================添加查询规则======================
        /*
            private String chargeName;// 	null
            private Long courseTypeId;// 	null
            private String gradeName;// 	null
            private BigDecimal priceMax;// 	null
            private BigDecimal priceMin;// 	null
         */
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(StringUtils.hasLength(dto.getChargeName())){
            boolQuery.filter(QueryBuilders.termQuery("chargeName",dto.getChargeName()));
        }
        if (dto.getCourseTypeId()!=null && dto.getCourseTypeId()!=0){
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId",dto.getCourseTypeId()));
        }
        if (StringUtils.hasLength(dto.getGradeName())){
            boolQuery.filter(QueryBuilders.termQuery("gradeName",dto.getGradeName()));
        }
        if (dto.getPriceMax()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        if (dto.getPriceMin()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        if (StringUtils.hasLength(dto.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
        }
        searchQueryBuilder.withQuery(boolQuery);

        //===================高亮处理==================================
        /*
            在分词以后的关键字 添加标签
         */
        HighlightBuilder.Field name = new HighlightBuilder.Field("name");
        //设置前缀，后缀
        name.preTags("<font style='color:red'>").postTags("</font>");

        searchQueryBuilder.withHighlightFields(name);
        //====================聚合处理============================
        //等级
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName");
        //收费规则
        TermsAggregationBuilder chargeNameAgg = AggregationBuilders.terms("chargeNameAgg").field("chargeName");
        searchQueryBuilder.addAggregation(chargeNameAgg).addAggregation(gradeNameAgg);
        //=====================结果集处理============================
        //es的搜索
        SearchQuery query = searchQueryBuilder.build();
        //执行查询以后得到结果
        //Page<CourseDoc> pageDocs = courseDocRepository.search(query);
        AggregatedPage<CourseDoc> pageDocs = restTemplate.queryForPage(query, CourseDoc.class, highlightResultMapper);

        //聚合以后所有的结果集
        Aggregations aggregations = pageDocs.getAggregations();
        Map<String, Aggregation> map = aggregations.asMap();

        //最终要返回到前端的数据
        Map<String,List<BucketVo>> mapList = new HashMap<>();
        map.entrySet().forEach(entry->{
            //装相同类型的数据
            List<BucketVo> listBucketVo = new ArrayList<>();

            //每一次聚合结果集
            ParsedStringTerms value = (ParsedStringTerms) entry.getValue();
            List<? extends Terms.Bucket> list = value.getBuckets();
            list.forEach(bucket -> {
                BucketVo bucketVo = new BucketVo(bucket.getKeyAsString(), bucket.getDocCount());
                listBucketVo.add(bucketVo);
            });

            mapList.put(entry.getKey(),listBucketVo);
        });


        //pageDocs.getTotalElements(); 获取总条数
        //pageDocs.getContent();获取里面的数据的集合
        System.out.println(pageDocs.getContent());
        return new AggPageList(pageDocs.getTotalElements() , pageDocs.getContent(),mapList);
    }
}
